###############################################################################
#
# file: EditUnitDialog.py
# author: Victor Bos
# 
# Copyright 2007--2011 Victor Bos
#
# This file is part of GREATOR.
#
#    GREATOR is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    GREATOR is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with GREATOR.  If not, see <http://www.gnu.org/licenses/>.
#
###############################################################################
import StringIO

import ScrolledText
import Tkinter
import Tkconstants

import io

FG_BORDER_WIDTH=5

CANCEL = 0
DELETED = 1
CHANGED = 2

class EditUnitTypeDialog(Tkinter.Toplevel):

    init_filename = ""

    def __init__(self, master=None, **kw):

        self.is_name_editable = kw.get("is_name_editable", True)
        if "is_name_editable" in kw:
            del kw["is_name_editable"]

        self.process_options(kw)
        Tkinter.Toplevel.__init__(self, master, kw)
        self.protocol('WM_DELETE_WINDOW', self.cancel_pressed)
        self.title(self.windowtitle)

        lframe = Tkinter.LabelFrame(
            self, 
            text=self.message)
        lframe.pack(side = Tkinter.TOP, fill=Tkinter.BOTH, expand=1)

        self.unit_type = None
        self.unit_name = Tkinter.StringVar()
        f1 = self.create_main_frame(lframe)
        if f1 is not None:
            f1.pack(side = Tkinter.TOP, expand=1, fill=Tkinter.BOTH, padx=10, pady=10)

        f2 = self.create_ok_cancel_buttons()
        f2.pack(
            side = Tkinter.TOP, 
            anchor = Tkinter.SW, 
            fill = Tkinter.X, 
            expand=1)

        self.result = CANCEL
        self.center_on_master(master)

    def clear_attr_text(self):
        if self.attr_text is not None:
            self.attr_text.delete("1.0",Tkinter.END)

    def append_attr_text(self, s):
        self.attr_text.insert(Tkinter.END, s)

    def set_unit_type(self, utp, bitmap_data):
        self.unit_type = utp
        self.bitmap_data = bitmap_data
        self.unit_name.set(utp.name)
        self.clear_attr_text()
        self.append_attr_text(self.get_attr_str())
        self.set_icon_button()

    def get_unit_type(self):
        self.unit_type.name = self.get_unit_name()
        return self.unit_type

    def set_icon_button(self):
        self.xbm = Tkinter.BitmapImage(data = self.bitmap_data)
        if ((self.xbm.width() == 0) or 
            (self.xbm.height() == 0)):
            self.icon_button['bitmap'] = "gray25"
        else:
            self.icon_button['image'] = self.xbm

    def create_main_frame(self, lframe):
        f = Tkinter.Frame(lframe)
        
        self.icon_button = Tkinter.Button(f, command = self.change_icon_button)
        self.icon_button.grid(
            row = 0,
            column = 0,
            sticky = "w")
        editstate = Tkinter.NORMAL
        if not self.is_name_editable:
            editstate = Tkinter.DISABLED
        self.name_entry = Tkinter.Entry(
            f, 
            textvariable=self.unit_name,
            state = editstate)
        self.name_entry.grid(
            row=0,
            column=1,
            sticky="ew")
        
        self.attr_text = ScrolledText.ScrolledText(
            f,
            bd=FG_BORDER_WIDTH,
            width=1,
            height=8,
            background="ghostwhite")
        self.attr_text.grid(
            row=1,
            column=0,
            columnspan=2,
            sticky="nesw")
        self.attr_text.bind(
            "<Leave>",
            lambda e: self.update_attrs())

        f.columnconfigure(1, weight=1)
        f.rowconfigure(1, weight=1)
        return f
    
    def update_attrs(self):
        self.buffer = []
        self.attr_text.dump(
            "1.0",
            Tkinter.END,
            command=self.filter_text,
            text=True)
        attrs_str = ("".join(self.buffer)).strip()
        attrs = io.read_attrs(attrs_str)
        self.set_unit_type_attrs(attrs)

    def set_unit_type_attrs(self, attrs):
        if self.unit_type is not None:
            self.unit_type.attrs = attrs
            self.result = CHANGED

    def filter_text(self, k, v, i):
        self.buffer.append(v)

    def get_attr_str(self, spc=""):
        return io.attrs_to_str(self.unit_type.attrs, spc=spc)

    def change_icon_button(self):
        if self.unit_type is not None:
            filename = io.open_load_dialog(
                self.init_filename,
                "icon.xbm",
                "Bitmap files")
            if filename:
                f = open(filename, 'rb')
                self.bitmap_data = f.read()
                f.close()
                self.set_icon_button()
                self.result = CHANGED
                self.init_filename = filename
                
    def create_ok_cancel_buttons(self):
        f = Tkinter.Frame(self)

        self.delete_button = Tkinter.Button(
            f,
            text="Delete",
            command=self.delete_pressed)
        self.delete_button.pack(side=Tkinter.LEFT)

        Tkinter.Label(f).pack(side=Tkinter.LEFT, expand=1)

        self.ok_button = Tkinter.Button(
            f,
            text="Ok",
            command=self.ok_pressed)
        self.ok_button.pack(side=Tkinter.LEFT)

        self.cancel_button = Tkinter.Button(
            f,
            text="Cancel",
            command=self.cancel_pressed)
        self.cancel_button.pack(side=Tkinter.LEFT)
        return f
    
    def center_on_master(self, master):
        if master is not None:
            x = (master.winfo_rootx() +
                 ((master.winfo_width() - self.winfo_reqwidth()) / 2.0))
            y = (master.winfo_rooty() +
                 ((master.winfo_height() - self.winfo_reqheight()) / 2.0))
            self.geometry("+%d+%d" % (x,y))
        
    def process_options(self, kw):
        self.set_option("message", kw, "Edit unit type")
        self.set_option("windowtitle", kw, "Unit type editor")
        
    def set_option(self, name, user_values, default):
        if name in user_values:
            setattr(self, name, user_values[name])
            del user_values[name]
        else:
            setattr(self, name, default)

    def delete_pressed(self):
        self.result = DELETED
        self.quit()

    def ok_pressed(self):        
        uname = self.unit_name.get()
        self.quit()

    def get_unit_name(self):
        return self.unit_name.get()

    def get_bitmap_data(self):
        return self.bitmap_data

    def cancel_pressed(self):
        self.result = CANCEL
        self.quit()

    def go(self):
        self.wait_visibility() # window needs to be visible for the grab
        self.grab_set()
        self.mainloop()
        return self.result

class EditUnitDialog(EditUnitTypeDialog):

    def set_unit(self, unit, bitmap_data):
        self.set_unit_type(unit, bitmap_data)

    def get_unit(self):
        return self.unit_type

    def process_options(self, kw):
        self.set_option("message", kw, "Edit unit")
        self.set_option("windowtitle", kw, "Unit editor")
        
